package com.naiterui.ehp.bs.pharmacist.controller;

import cn.hutool.json.JSONUtil;
import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.constants.CommonConstant;
import com.naiterui.ehp.bp.constants.SwaggerTag;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.support.exception.PublicService;
import com.naiterui.ehp.bp.support.exception.ResponseVO;
import com.naiterui.ehp.bp.support.security.HeaderConstant;
import com.naiterui.ehp.bp.support.utils.IpUtil;
import com.naiterui.ehp.bp.utils.encypt.DESPlus;
import com.naiterui.ehp.bp.utils.encypt.RSAUtil;
import com.naiterui.ehp.bp.utils.esign.ESignUtils;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bp.utils.lang.StringUtil;
import com.naiterui.ehp.bp.utils.sms.SMSUtil;
import com.naiterui.ehp.bs.pharmacist.entity.Pharmacist;
import com.naiterui.ehp.bs.pharmacist.exception.ExceptionCodes;
import com.naiterui.ehp.bs.pharmacist.service.IEsignUserService;
import com.naiterui.ehp.bs.pharmacist.service.ILoginService;
import com.naiterui.ehp.bs.pharmacist.service.ITencentDetectService;
import com.naiterui.ehp.bs.pharmacist.utils.Constants;
import com.naiterui.ehp.bs.pharmacist.utils.LimitValueConfig;
import com.naiterui.ehp.bs.pharmacist.vo.login.AuthFlowParamVO;
import com.naiterui.ehp.bs.pharmacist.vo.login.AuthFlowVO;
import com.naiterui.ehp.bs.pharmacist.vo.login.LoginVO;
import com.naiterui.ehp.bs.pharmacist.vo.user.AuthRegistCacheVO;
import com.naiterui.ehp.bs.pharmacist.vo.user.RegistVO;
import com.naiterui.ehp.bs.pharmacist.vo.user.RegisterParamVO;
import com.naiterui.ehp.bs.pharmacist.vo.user.TencentFaceIdVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.naiterui.ehp.bs.pharmacist.utils.ChackPasswordUtils.validPwd;

/**
 * @Description 登陆接口
 * @Author gongbaoqiang
 * @Date 2019/11/30 6:18 PM
 */
@RequestMapping("pharmacist/login")
@Api(description = "登陆接口", tags = SwaggerTag.PHARMACIST + SwaggerTag.USER_ACCOUNT)
@Slf4j
@Validated
@RestController
public class PharmacistLoginController {

    @Autowired
    private ILoginService loginService;
    @Autowired
    private ITencentDetectService tencentDetectService;
    @Autowired
    private IEsignUserService userService;

    /**
     * 药师注册验证
     * @deprecated 业务流程调整，该接口合并到实名信息初始化中校验 {@link #authFlow(AuthFlowParamVO)}
     * @param phoneNum   药师输入手机号码
     * @param verifyCode 验证码
     * @return
     */
    @Deprecated
    @PostMapping(value = "/validateRegist")
    public void validateRegist(String phoneNum, String verifyCode) throws BusinessException {

        // 1.判断手机号的非空和格式
        this.validPhone(phoneNum);
        // 2.判断短信验证码的非空和正确性
        String redisKey = Constants.PHONE_REGIST_KEY + phoneNum;
        SMSUtil.validCode(verifyCode, redisKey, CommonConstant.REDIS_PRE_PHARMACIST);
        // 3. cache中记录验证成功，验证码存放10分钟
        String cacheKey = Constants.PHONE_VALID_REGIST_KEY + phoneNum;
        RedisUtil.valueOps().set(cacheKey, "", Constants.SAVE_VERIFY_CODE);
    }

    /**
     * 获取实名认证流程信息
     * 验证短信验证码，并校验注册信息是否与数据库信息匹配
     * @param flowParamVO
     */
    @ApiOperation(value = "获取实名认证流程信息")
    @PostMapping(value = "/authFlow")
    public AuthFlowVO authFlow(@Valid AuthFlowParamVO flowParamVO) throws BusinessException {
        return this.loginService.authFlow(flowParamVO);
    }


    @ApiOperation(value = "药师注册并校验实名认证结果")
    @PostMapping(value = "/authRegist")
    public ResponseVO<RegistVO> authRegist(@NotEmpty(message = "authId不能为空") String authId) throws BusinessException {
        return this.loginService.authRegist(authId);
    }

    /**
     * 药师注册
     * @deprecated 注册实名流程调整，使用 {@link #authRegist(String)}
     * @return
     */
    @Deprecated
    @PostMapping(value = "/regist")
    public RegistVO regist(RegisterParamVO paramVO) throws BusinessException {
        log.info("药师注册:paramVO={}", JSONUtil.toJsonStr(paramVO));
        String phoneNum = paramVO.getPhoneNum();
        String password = paramVO.getPassword();
        String cardNo = paramVO.getCardNo();
        MultipartFile sealImg = paramVO.getSealImg();

        // 1.判断手机号的非空和格式
        this.validPhone(phoneNum);

        // 3.判断密码的非空和格式
        String pwd = validPwd(phoneNum, password);
        paramVO.setPassword(pwd);

        // 4.判断注册验证手机是否超时
        // 注册验证通过验证判断
        String cacheKey = Constants.PHONE_VALID_REGIST_KEY + phoneNum;
        if (!RedisUtil.keyOps().existsKey(cacheKey)) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_VALID_FAIL);
        }

        if (ESignUtils.isHandWriting() && sealImg == null) {
            log.error("药师手写签名不能为空");
            throw new BusinessException(ExceptionCodes.SEAL_IMAGE_NOT_NULL);
        }

        RegistVO registVO = this.loginService.saveLogin(paramVO);
        RedisUtil.keyOps().delete(Constants.PHONE_REGIST_KEY + phoneNum);
        return registVO;
    }


    @PostMapping(value = "/getPublicKey")
    public Map<String, String> getRSAPublicKey() throws Exception {
        String key = RSAUtil.getPublicKeyStr();
        Map<String, String> map = new HashMap<>();
        map.put("publicKey", key);

        return map;
    }

    /**
     * 登陆获取loginKey
     *
     * @param phoneNum
     * @return
     */
    @PostMapping(value = "/genLoginKey")
    public Map<String, String> genLoginKey(String phoneNum) throws BusinessException {
        // 1.判断手机号是否合法
        if (phoneNum == null || "".equals(phoneNum)) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_NULL);
        }
        if (!StringUtil.isMobileNum(phoneNum)) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_ERROR);
        }

        // 2.根据手机查询用户信息
        Pharmacist login = this.loginService.findLoginByPhoneNum(phoneNum);

        if (login == null) {
            throw new BusinessException(ExceptionCodes.PHARMACIST_ACCOUNT_NOT_EXISTS);
        }

        // 3.获取用户id和盐
        long pharmacistId = login.getId();
        String salt = login.getSalt();
        Map<String, String> map = new HashMap<>();
        map.put("pharmacistId", String.valueOf(pharmacistId));
        String loginKey = DESPlus.gengerateLoginKey(pharmacistId, salt);
        map.put("loginKey", loginKey);

        String cacheKey = Constants.PHARMACIST_LOGIN_KEY + pharmacistId;
        RedisUtil.valueOps().set(cacheKey, loginKey, Constants.SAVE_VERIFY_CODE);
        return map;
    }


    /**
     * 用户登录
     */
    @PostMapping("login")
    @ApiOperation(value = "根据药师ID获取详细信息", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({@ApiImplicitParam(name = "pharmacistId", value = "药师id", required = true, dataType = "long", paramType = "query"),
            @ApiImplicitParam(name = "loginKey", value = "登录key", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "password", value = "登陆密码", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "deviceSN", value = "设备sn", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "authId", value = "认证ID(注册后自动登录必传)", dataType = "String", paramType = "query"),
    })
    public ResponseVO<LoginVO> login(@RequestParam(value = "pharmacistId", required = false) Long loginId, String loginKey, String password,
                                     String deviceSN, String authId, HttpServletRequest request) throws BusinessException {

        String _p = request.getHeader(HeaderConstant.HEADER_PLATFORM);
        String _v = request.getHeader(HeaderConstant.HEADER_VERSION);
        log.info("用户登陆接口 请求参数：loginId = [{}], loginKey = [{}], password = [{}], deviceSN = [{}], _p = [{}], _v = [{}]", loginId, loginKey,
                password, deviceSN, _p, _v);

        // 1.登录参数校验
        if (loginId == null || loginKey == null) {
            log.info("参数异常，药师id:{},loginKey:{}", loginId, loginKey);
            throw new BusinessException(ExceptionCodes.PARAM_ERROR);
        }

        if (StringUtils.isEmpty(password)) {
            log.info("密码空，药师id:{}，password:{}", loginId, password);
            throw new BusinessException(ExceptionCodes.REGIST_PWD_NULL);
        }
        try {
            password = password.replaceAll(" ", "+");
            password = RSAUtil.decryptByPrivateKey(password);
        } catch (Exception e) {
            log.error("密码解密异常，loginId={}", loginId, e);
            throw new BusinessException(ExceptionCodes.FAILED);
        }

        if (StringUtils.isEmpty(password)) {
            throw new BusinessException(ExceptionCodes.REGIST_PWD_NULL);
        }
        password = password.trim();

        // 2.根据loginId判断用户信息，并返回登录信息
        LoginVO loginVO = this.loginService.saveLoginInfoById(loginId, loginKey, password, _v, _p, deviceSN, authId, request);

        return PublicService.returnResponseVO(loginVO);
    }

    /**
     * <登出，清除token信息> <详细描述>
     *
     * @param pharmacistId
     * @param token
     * @return String <返回值描述>
     * @Throws 异常信息
     */
    @PostMapping(value = "/logout")
    @ApiOperation(value = "根据药师ID获取详细信息", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pharmacistId", value = "药师id", required = true, dataType = "long",
                    paramType = "query"),
            @ApiImplicitParam(name = "deviceSN", value = "设备sn", required = true, dataType = "String",
                    paramType = "query"),})
    public void logout(Long pharmacistId, String token, String deviceSN, HttpServletRequest request) throws BusinessException {

        // 2.获取登陆信息，退出
        Pharmacist login = this.loginService.findById(pharmacistId);

        String dbToken = login.getToken();
        if (dbToken == null || "".equals(dbToken)) {
            return;
        }

        // 3.验证id和token
        if (!dbToken.equals(token)) {
            throw new BusinessException(ExceptionCodes.FAILED);
        }

        // 是否不互踢
        boolean loginKickEachOther = RedisUtil.keyOps().existsKey(Constants.PHARMACIST_LOGIN_KICK_EACH_OTHER);
        // 4.如果不互踢逻辑未开启，清除数据库中token
        if (!loginKickEachOther) {
            login.setToken(null);
        }
        login.setChangedAt(new Date(System.currentTimeMillis()));
        this.loginService.updateLogin(login);
        // 登出日志
        String model = request.getHeader(HeaderConstant.HEADER_MODEL);
        String ip = IpUtil.getIp(request);
        String loginAddr = IpUtil.getCityInfo(ip);
        this.loginService.saveLogoutLog(login, model, ip, loginAddr, deviceSN);

        // 如果不互踢逻辑未开启，清理药师登录TOKEN
        if (!loginKickEachOther) {
            String cacheKey = Constants.PHARMACIST_LOGIN_TOKEN_KEY + pharmacistId;
            RedisUtil.keyOps().delete(cacheKey);
        }
    }

    /**
     * 短信验证码验证登录 LoginController.validPhoneCodeLogin()
     *
     * @param phoneNum
     * @param verifyCode
     * @param deviceSN
     * @param request
     * @return
     * @Author chenlin
     * @Date 2016年3月28日
     * @since 1.0.0
     */
    @PostMapping("validLogin")
    @ApiOperation(value = "根据药师ID获取详细信息", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phoneNum", value = "手机号", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "verifyCode", value = "验证码", required = true, dataType = "String",
                    paramType = "query"),
            @ApiImplicitParam(name = "deviceSN", value = "设备sn", required = true, dataType = "String",
                    paramType = "query"),})
    public ResponseVO<LoginVO> validPhoneCodeLogin(String phoneNum, String verifyCode, String deviceSN
        , HttpServletRequest request) throws BusinessException {

        String _p = request.getHeader(HeaderConstant.HEADER_PLATFORM);
        String _v = request.getHeader(HeaderConstant.HEADER_VERSION);
        // 1.判断手机号是否合法
        this.validPhone(phoneNum);

        // 2.判断短信验证码的非空和正确性
        String redisKey = Constants.PHONE_LOGIN_PWD_KEY + phoneNum;
        SMSUtil.validCode(verifyCode, redisKey, CommonConstant.REDIS_PRE_PHARMACIST);

        // 3.判断药师是否注册，注册直接登录，未注册进行注册。
        LoginVO loginVO = this.loginService.saveLoginInfoByPhone(phoneNum, _v, _p, deviceSN, request);
        RedisUtil.keyOps().delete(redisKey);
        return PublicService.returnResponseVO(loginVO);
    }

    /**
     * 密码 + 短信验证码验证登录 LoginController.combineLogin()
     */
    @PostMapping("combine")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pharmacistId", value = "药师id", required = true, dataType = "long",
                    paramType = "query"),
            @ApiImplicitParam(name = "loginKey", value = "登录key", required = true, dataType = "String",
                    paramType = "query"),
            @ApiImplicitParam(name = "password", value = "登陆密码", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "deviceSN", value = "设备sn", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "phoneNum", value = "手机号", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "verifyCode", value = "验证码", required = true, dataType = "String",
                    paramType = "query"),})
    public ResponseVO<LoginVO> combineLogin(
            @RequestParam(value = "pharmacistId", required = false) Long loginId,
            String loginKey,
            String password,
            String deviceSN,
            String phoneNum,
            String verifyCode,
            @RequestHeader String _p,
            @RequestHeader String _v,
            HttpServletRequest request) throws BusinessException {

        log.info("用户登陆接口 请求参数：loginId = [{}], loginKey = [{}], password = [{}], deviceSN = [{}], _p = [{}], _v = [{}]", loginId, loginKey,
                password, deviceSN, _p, _v);

        // 1.登录参数校验
        if (loginId == null || loginKey == null) {
            log.info("参数异常，药师id:{},loginKey:{}", loginId, loginKey);
            throw new BusinessException(ExceptionCodes.PARAM_ERROR);
        }

        if (StringUtils.isEmpty(password)) {
            log.info("密码空，药师id:{}，password:{}", loginId, password);
            throw new BusinessException(ExceptionCodes.REGIST_PWD_NULL);
        }
        try {
            password = password.replaceAll(" ", "+");
            password = RSAUtil.decryptByPrivateKey(password);
        } catch (Exception e) {
            log.error("密码解密异常，loginId={}", loginId, e);
            throw new BusinessException(ExceptionCodes.FAILED);
        }

        if (StringUtils.isEmpty(password)) {
            throw new BusinessException(ExceptionCodes.REGIST_PWD_NULL);
        }
        password = password.trim();

        // 判断手机号是否合法
        this.validPhone(phoneNum);

        // 判断短信验证码的非空和正确性
        String redisKey = Constants.PHONE_LOGIN_PWD_KEY + phoneNum;
        SMSUtil.validCode(verifyCode, redisKey, CommonConstant.REDIS_PRE_PHARMACIST);

        // 判断药师是否注册，注册直接登录，未注册进行注册。
        LoginVO loginVO = this.loginService.saveLoginCombine(loginId, loginKey, password, phoneNum, _v, _p, deviceSN, request);
        RedisUtil.keyOps().delete(redisKey);
        return PublicService.returnResponseVO(loginVO);
    }

    @PostMapping("/validateForgetPwd")
    @ApiOperation(value = "忘记密码验证手机号")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phoneNum", value = "手机号", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "verifyCode", value = "验证码", required = true, dataType = "String", paramType = "query"),
    })
    public void validateForgetPwd(String phoneNum, String verifyCode) throws BusinessException {
        if (phoneNum == null || "".equals(phoneNum)) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_NULL);
        }
        if (!StringUtil.isMobileNum(phoneNum)) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_ERROR);
        }

        String redisKey = Constants.PHONE_FORGET_KEY + phoneNum;
        this.validCode(verifyCode, redisKey);
        Pharmacist pharmacist = this.loginService.findLoginByPhoneNum(phoneNum);
        if (null == pharmacist) {
            throw new BusinessException(ExceptionCodes.PHARMACIST_ACCOUNT_NOT_EXISTS);
        }

        // cache中记录验证成功，验证码存放10分钟
        String cacheKey = Constants.PHONE_VALID_FORGET_KEY + phoneNum;
        RedisUtil.valueOps().set(cacheKey, "", Constants.SAVE_VERIFY_CODE);

    }

    @PostMapping(value = "/setForgetPwd")
    @ApiOperation(value = "忘记密码设置密码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phoneNum", value = "手机号", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "password", value = "登陆密码", required = true, dataType = "String", paramType = "query"),
    })
    public void setForgetPwd(String phoneNum, String password) throws BusinessException {

        // 1.电话是否正确
        if (phoneNum == null || "".equals(phoneNum)) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_NULL);
        }
        if (!StringUtil.isMobileNum(phoneNum)) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_ERROR);
        }

        password = validPwd(phoneNum, password);

        // 4.根据手机查询用户信息
        Pharmacist pharmacist = this.loginService.findLoginByPhoneNum(phoneNum);

        if (pharmacist == null) {
            throw new BusinessException(ExceptionCodes.REGIST_EXSIT);
        }

        // 5.判断忘记密码验证手机是否超时
        String cacheKey = Constants.PHONE_VALID_FORGET_KEY + phoneNum;
        if (!RedisUtil.keyOps().existsKey(cacheKey)) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_VALID_FAIL);
        }

        // 6.保存密码
        this.loginService.savePassword(pharmacist, password);
        RedisUtil.keyOps().delete(Constants.PHONE_FORGET_KEY + phoneNum);
        RedisUtil.keyOps().delete(cacheKey);
    }

    /**
     * 登陆重置密码
     *
     * @param pharmacistId
     * @param phoneNum
     * @param verifyCode
     * @param newPwd
     * @return
     */
    @PostMapping(value = "/setPharmacistPwd")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pharmacistId", value = "药师id", required = true, dataType = "long",
                    paramType = "query"),
            @ApiImplicitParam(name = "phoneNum", value = "手机号", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "verifyCode", value = "验证码", required = true, dataType = "String",
                    paramType = "query"),
            @ApiImplicitParam(name = "newPwd", value = "新密码", required = true, dataType = "String", paramType = "query"),})
    public void setDoctorPwd(Long pharmacistId, String phoneNum, String verifyCode, String newPwd) throws Exception {

        if (pharmacistId == null) {
            log.info("参数异常，药师id:{}", pharmacistId);
            throw new BusinessException(ExceptionCodes.PARAM_ERROR);
        }

        // 1.密码解密
        newPwd = newPwd.replaceAll(" ", "+");
        newPwd = RSAUtil.decryptByPrivateKey(newPwd);

        // 2.密码是否符合规则
        if ("".equals(newPwd)) {
            throw new BusinessException(ExceptionCodes.REGIST_PWD_NULL);
        }

        newPwd = newPwd.trim();
        if (!LimitValueConfig.validateLimit(LimitValueConfig.LIMIT_PASSWORD, newPwd)) {
            throw new BusinessException(ExceptionCodes.REGIST_PWD_ERROR);
        }
        /*if (!ChackPasswordUtils.validatePassword(newPwd)) {
            throw new BusinessException(ExceptionCodes.PASSWORD_UNQUALIFIED);
        }*/

        String redisKey = Constants.PHONE_MODIFY_PWD_KEY + phoneNum;
        SMSUtil.validCode(verifyCode, redisKey, CommonConstant.REDIS_PRE_PHARMACIST);

        // 4.根据用户id，查询用户信息
        Pharmacist pharmacist = this.loginService.findById(pharmacistId);

        if (pharmacist == null) {
            log.error("获取药师信息异常");
            throw new BusinessException(ExceptionCodes.FAILED);
        }

        // 6.验证手机
        if (phoneNum == null || "".equals(phoneNum)) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_NULL);
        }
        String srcPhone = pharmacist.getPhone();
        if (!phoneNum.equals(srcPhone)) {
            throw new BusinessException(ExceptionCodes.LOGIN_PWD_PHONE_FAIL);
        }

        // 7.保存密码
        this.loginService.savePassword(pharmacist, newPwd);
        RedisUtil.keyOps().delete(Constants.PHONE_REGIST_KEY + phoneNum);
        RedisUtil.keyOps().delete(redisKey);
        RedisUtil.keyOps().delete(Constants.RDS_KEY_LAST_MODIFY + pharmacistId);

    }

    /**
     * 获取腾讯云人脸识别参数
     * @deprecated 流程调整接口废弃，获取实名认证流程信息中获取 {@link #authFlow(AuthFlowParamVO)}
     * @param phone
     * @param cardNo
     * @return
     * @throws BusinessException
     */
    @Deprecated
    @PostMapping("/faceid")
    @ApiOperation(value = "获取人脸识别初始化参数-药师", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "药师手机", required = true, dataType = "long", paramType = "form"),
            @ApiImplicitParam(name = "cardNo", value = "药师身份证号", required = true, dataType = "long", paramType = "form"),

    })
    public ResponseVO<TencentFaceIdVO> getFaceId(String phone, String cardNo) throws BusinessException {
        TencentFaceIdVO tencentFaceIdVO = tencentDetectService.getFaceId(phone, cardNo);
        return PublicService.returnResponseVO(ExceptionCodes.SUCCESS, tencentFaceIdVO);
    }

    /**
     * <获取实名认证验证码>
     * 
     * @param authId
     * @return
     * @throws BusinessException
     */
    @PostMapping("realname/code")
    @ApiOperation(value = "获取实名认证验证码", httpMethod = "POST")
    @ApiImplicitParam(name = "authId", value = "认证流程Id", required = true, dataType = "String")
    public ResponseVO<Void> realnameCode(@RequestParam String authId) throws BusinessException {
        log.info("获取实名认证验证码 请求参数：authId = [{}]", authId);
        AuthRegistCacheVO authRegistCacheVO = Constants.getRdsPhAuthId(authId);
        if (null == authRegistCacheVO || authRegistCacheVO.getId() == null) {
            throw new BusinessException(ExceptionCodes.PARAM_ERROR, "非法访问");
        }
        userService.getRealnameCode(authRegistCacheVO.getId());
        return PublicService.returnResponseVO(ExceptionCodes.SUCCESS);
    }

    @PostMapping("realname/check")
    @ApiOperation(value = "实名认证", httpMethod = "POST")
    @ApiImplicitParams({@ApiImplicitParam(name = "authId", value = "认证流程Id", required = true, dataType = "String"),
        @ApiImplicitParam(name = "code", value = "验证码", required = true, dataType = "string")})
    public ResponseVO<Void> realnameCheck(@RequestParam String authId, String code) throws BusinessException {
        log.info("实名认证 请求参数：authId = [{}], code={}", authId, code);
        AuthRegistCacheVO authRegistCacheVO = Constants.getRdsPhAuthId(authId);
        if (null == authRegistCacheVO || authRegistCacheVO.getId() == null) {
            throw new BusinessException(ExceptionCodes.PARAM_ERROR, "非法访问");
        }
        userService.checkRealnameCode(authRegistCacheVO.getId(), code);
        Constants.setRdsPhAuthIdCheck(authId, code);
        return PublicService.returnResponseVO(ExceptionCodes.SUCCESS, ConfigUtil.getString("pharmacist.realname.check"),
            null);
    }


    /**
     * 验证手机号根式和非空 LoginController.validPhone()
     *
     * @param phoneNum
     * @throws BusinessException
     * @Author chenlin
     * @Date 2016年3月25日
     * @since 1.0.0
     */
    private void validPhone(String phoneNum) throws BusinessException {
        if (phoneNum == null || "".equals(phoneNum)) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_NULL);
        }
        if (!StringUtil.isMobileNum(phoneNum)) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_ERROR);
        }
    }

    /**
     * 验证手机号获取验证码是否正确
     * LoginController.validCode()
     *
     * @param verifyCode
     * @param redisKey
     * @throws BusinessException
     * @Author chenlin
     * @Date 2016年3月25日
     * @since 1.0.0
     */
    private void validCode(String verifyCode, String redisKey) throws BusinessException {
        if (verifyCode == null || "".equals(verifyCode)) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_VALID_NULL);
        }
        String cacheVerifyCode = RedisUtil.valueOps().getString(redisKey);
        if (StringUtils.isEmpty(cacheVerifyCode)) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_VALID_ERROR);
        }
        if (!verifyCode.trim().equalsIgnoreCase(cacheVerifyCode)) {
            // 连续输入错误次数控制
            if (this.loginService.validUserOperator(redisKey)) {
                RedisUtil.keyOps().delete(redisKey);
                throw new BusinessException(ExceptionCodes.SMS_PHONE_VALID_ERROR);
            }
            throw new BusinessException(ExceptionCodes.SMS_PHONE_VALID_ERROR);
        }
    }

}
